package soar.template.springboot.service.hello.configuration.filter;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ReadListener;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
public class MyHttpServletRequestFilter implements Filter
{
    @SuppressWarnings("unused")
    private final static Logger logger = LoggerFactory
            .getLogger(MyHttpServletRequestFilter.class);

    @Override
    public void init(FilterConfig config) throws ServletException
    {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException
    {
        if (request instanceof HttpServletRequest)
        {
            ServletRequest request_wrapper=new BodyReaderHttpServletRequestWrapper(
                    (HttpServletRequest) request);
            chain.doFilter(request_wrapper, response);
        }
        else
        {
            chain.doFilter(request, response);
        }
    }

    @Override
    public void destroy()
    {
    }

}

class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper
{
    @SuppressWarnings("unused")
    private final static Logger logger = LoggerFactory
            .getLogger(BodyReaderHttpServletRequestWrapper.class);

    private final byte[] body;

    public BodyReaderHttpServletRequestWrapper(HttpServletRequest request)
            throws IOException
    {
        super(request);

        byte[] body = new byte[0];
        byte[] buf = new byte[100 * 1024];
        InputStream in = request.getInputStream();
        int bytes;
        while ((bytes = in.read(buf)) != -1)
        {
            byte[] tmp = new byte[body.length + bytes];
            System.arraycopy(body, 0, tmp, 0, body.length);
            System.arraycopy(buf, 0, tmp, body.length, bytes);
            body = tmp;
        }
        this.body = body;
        
//        logger.info("construct");
    }

    @Override
    public BufferedReader getReader() throws IOException
    {
//        logger.info("reader");
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }

    @Override
    public ServletInputStream getInputStream() throws IOException
    {
//        logger.info("stream");
        
        final ByteArrayInputStream bais = new ByteArrayInputStream(body);

        return new ServletInputStream()
        {

            @Override
            public int read() throws IOException
            {
                return bais.read();
            }

            @Override
            public boolean isFinished()
            {
                return bais.available() == 0;
            }

            @Override
            public boolean isReady()
            {
                return true;
            }

            @Override
            public void setReadListener(ReadListener arg0)
            {
                throw new RuntimeException("Not implemented");
            }

        };
    }
}